#include <dim-sum/types.h>
#include <dim-sum/boot_allotter.h>
#include <dim-sum/beehive.h>
#include <dim-sum/mem.h>
#include <dim-sum/sched.h>
#include <dim-sum/exec.h>
#include <dim-sum/mm_types.h>
#include <dim-sum/smp.h>
#include <dim-sum/psci.h>
#include <asm/exception.h>
#include <asm/alternative.h>
#include <asm/cpufeature.h>
#include <asm/processor.h>
#include <asm/current.h>
#include <asm/asm-offsets.h>

extern union process_union *idle_proc_stacks[];
extern struct task_desc *idle_task_desc[];
/**
 * CPU功能位图
 */
DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);

typedef unsigned long (psci_fn)(unsigned long, unsigned long,
				unsigned long, unsigned long);
#ifndef CONFIG_ARM64_PSCI_SMC 
asmlinkage psci_fn __invoke_psci_fn_hvc;
#else
asmlinkage psci_fn __invoke_psci_fn_smc;
#endif

#define PSCI_RET_SUCCESS			0
#define PSCI_RET_NOT_SUPPORTED			-1
#define PSCI_RET_INVALID_PARAMS			-2
#define PSCI_RET_DENIED				-3
#define PSCI_RET_ALREADY_ON			-4
#define PSCI_RET_ON_PENDING			-5
#define PSCI_RET_INTERNAL_FAILURE		-6
#define PSCI_RET_NOT_PRESENT			-7
#define PSCI_RET_DISABLED			-8
#define PSCI_RET_INVALID_ADDRESS		-9

static int psci_to_linux_errno(int errno)
{
	switch (errno) {
	case PSCI_RET_SUCCESS:
		return 0;
	case PSCI_RET_NOT_SUPPORTED:
		return -EOPNOTSUPP;
	case PSCI_RET_INVALID_PARAMS:
	case PSCI_RET_INVALID_ADDRESS:
		return -EINVAL;
	case PSCI_RET_DENIED:
		return -EPERM;
	};

	return -EINVAL;
}

#define cpu_logical_map(cpu) (cpu)

static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point)
{
	int err;
	u32 fn;

	fn = 0xc4000003;
#ifndef CONFIG_ARM64_PSCI_SMC
	err = __invoke_psci_fn_hvc(fn, cpuid, entry_point, 0);
#else
        err = __invoke_psci_fn_smc(fn, cpuid, entry_point, 0);
#endif 
	return psci_to_linux_errno(err);
}

int psci_launch_cpu(unsigned int cpu)
{
	int err = 0;
	phys_addr_t entry = linear_virt_to_phys(slave_cpu_entry);

	printk("xby_debug in psci_launch_cpu, pa is %p.\n", entry);
	err = psci_cpu_on(cpu_logical_map(cpu), entry);

	return err;
}

int arch_launch_cpu(unsigned int cpu, void* p)
{
	return psci_launch_cpu(cpu);
}

/**
 * 设置CPU相关选项
 * 例如探测CPU功能
 * 应用补丁等等
 */
void __init init_arch_cpu(void)
{
	/**
	 * 根据CPU特性，确定最终使用何种汇编指令
	 * 来实现特定的功能
	 * 相当于是给CPU打上动态补丁
	 */
	apply_alternatives_all();
}

/**
 * 调度模块早期初始化
 * 主要是初始化所有核上面的idle堆栈
 */
void init_sched_early(void)
{
	union process_union *stack;
	struct task_desc *proc;
	int i;
	for (i = 0; i < MAX_CPUS; i++)
	{
		if (i == 0)
		{
			idle_proc_stacks[i] = &master_idle_stack;
		}
		else
		{
			idle_proc_stacks[i] = alloc_boot_mem_permanent(PROCESS_STACK_SIZE,
									PROCESS_STACK_SIZE);

		}

		idle_task_desc[i] = alloc_boot_mem_permanent(sizeof(struct task_desc),
									cache_line_size());
		
		stack = idle_proc_stacks[i];
		proc = idle_task_desc[i];

		init_idle_process(stack, proc, i);

	}
}
